/**
 * 文件编辑接口测试用例
 *
 * Created by snowingsea on 2020/02/27.
 */
const path = require('path');
const randomstring = require('randomstring');

const chai = require('chai');
const should = chai.should(); // eslint-disable-line no-unused-vars
chai.use(require('chai-http'));

const common = require('./../../common');
const Administrator = require('./../../../models/administrator');
const uri = require('./../uri');

const files = require('./../../../../phoenix/models/files');

module.exports = describe('/PUT files/:id.json', function () {
  const administrator = new Administrator();
  let rootDirectory;
  const newUserIds = [];
  function url(fileId) {
    if (!fileId) {
      fileId = rootDirectory.fileId;
    }
    return `/files/${fileId}.json`;
  }

  before(function (done) {
    administrator.login()
      .then(() => administrator.createRandomTester())
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject();
      })
      .then((project) => project.createRandomVersion())
      .then((res) => {
        rootDirectory = res.rootDirectory;
        done();
      })
      .catch(done);
  });
  after(function (done) {
    administrator.removeUsers(newUserIds)
      .then(() => {
        done();
      })
      .catch(done);
  });

  common.should.be.user(uri, url, 'put');
  common.should.be.tester(uri, url, 'put');

  // 正常请求
  const body = [
    {},
    { content: randomstring.generate(100) },
    { content: '' },
  ];
  body.forEach((bodyEdit, bodyIndex) => {
    const query = [
      {},
      { fileName: randomstring.generate(8) },
      { fileName: path.join(randomstring.generate(8), randomstring.generate(8)) },
      { path: path.join(randomstring.generate(8), randomstring.generate(8)) },
      {
        fileName: randomstring.generate(8),
        path: path.join(randomstring.generate(8), randomstring.generate(8)),
      },
    ];
    query.forEach((queryEdit, queryIndex) => {
      it(`it should ${(queryIndex === 0 && bodyIndex === 0) ? 'PUT' : 'put'} a file with query: ${JSON.stringify(queryEdit)}, body: ${JSON.stringify(bodyEdit)}`, function (done) {
        let fileId;
        const preContent = randomstring.generate(101);
        rootDirectory.createEmptyFile(files.kind.file)
          .then((file) => {
            fileId = file.fileId;
            return file.updateContent(preContent);
          })
          .then(() => rootDirectory.projectVersion.project.creator.login())
          .then(() => {
            chai.request(uri)
              .put(url(fileId))
              .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
              .query(queryEdit)
              .send(bodyEdit)
              .end((err, res) => {
                res.should.have.status(200);
                common.should.be.fileMessage(res.body);
                let filePath;
                if (queryEdit.path) {
                  filePath = queryEdit.path;
                }
                if (queryEdit.fileName) {
                  if (filePath) {
                    filePath = path.join(path.dirname(filePath), queryEdit.fileName);
                  } else {
                    filePath = queryEdit.fileName;
                  }
                }
                if (filePath) {
                  res.body.fileName.should.be.eql(path.basename(filePath));
                  path.normalize(res.body.path).should.be.eql(path.normalize(filePath));
                } else {
                  res.body.fileId.should.be.eql(fileId);
                }
                if (!bodyEdit.content && bodyEdit.content !== '') {
                  res.body.content.should.be.eql(preContent);
                }
                Object.keys(bodyEdit).forEach((key) => {
                  res.body[key].should.be.eql(bodyEdit[key]);
                });
                done();
              });
          })
          .catch(done);
      });
    });
  });

  // 路径超出范围
  [
    { fileName: `../${randomstring.generate(8)}` },
    { path: `../../../${randomstring.generate(8)}` },
    {
      fileName: `../../../${randomstring.generate(8)}`,
      path: path.join(randomstring.generate(8), randomstring.generate(8)),
    },
  ].forEach((edit) => {
    it(`it should fail to put a file with ${JSON.stringify(edit)} when the path out of range`, function (done) {
      let fileId;
      const preContent = randomstring.generate(101);
      rootDirectory.createEmptyFile(files.kind.file)
        .then((file) => {
          fileId = file.fileId;
          return file.updateContent(preContent);
        })
        .then(() => rootDirectory.projectVersion.project.creator.login())
        .then(() => {
          chai.request(uri)
            .put(url(fileId))
            .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
            .query(edit)
            .end((err, res) => {
              res.should.have.status(403);
              common.should.be.errorMessage(res.body);
              done();
            });
        })
        .catch(done);
    });
  });

  // 不可编辑冻结项目的文件
  it('it should fail to put a file in frozen project', function (done) {
    let newProjectId;
    let newFileId;
    rootDirectory.projectVersion.project.creator.createRandomProject()
      .then((project) => {
        newProjectId = project.projectId;
        return project.createRandomVersion();
      })
      .then(({ rootDirectory }) => rootDirectory.createEmptyFile())
      .then((file) => {
        newFileId = file.fileId;
        return file.projectVersion.project.creator.freezeProject(newProjectId);
      })
      .then(() => rootDirectory.projectVersion.project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ content: '' })
          .end((err, res) => {
            res.should.have.status(403);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑冻结项目版本的文件
  it('it should fail to put a file in frozen project version', function (done) {
    let newVersionId;
    let newFileId;
    rootDirectory.projectVersion.project.createRandomVersion()
      .then(({ versionId, rootDirectory }) => {
        newVersionId = versionId;
        return rootDirectory.createEmptyFile();
      })
      .then((file) => {
        newFileId = file.fileId;
        return file.projectVersion.project.freezeVersion(newVersionId);
      })
      .then(() => rootDirectory.projectVersion.project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ content: '' })
          .end((err, res) => {
            res.should.have.status(403);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑他人项目的文件
  it('it should fail to put a file when the project is not yours', function (done) {
    let otherFileId;
    administrator.createRandomTester()
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject();
      })
      .then((project) => project.createRandomVersion())
      .then(({ rootDirectory }) => rootDirectory.createEmptyFile())
      .then((file) => {
        otherFileId = file.fileId;
        return rootDirectory.projectVersion.project.creator.login();
      })

      .then(() => {
        chai.request(uri)
          .put(url(otherFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ content: '' })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑不存在项目的文件
  it('it should fail to put a file when the project is not exist', function (done) {
    let newProjectId;
    let newFileId;
    rootDirectory.projectVersion.project.creator.createRandomProject()
      .then((project) => {
        newProjectId = project.projectId;
        return project.createRandomVersion();
      })
      .then(({ rootDirectory }) => rootDirectory.createEmptyFile())
      .then((file) => {
        newFileId = file.fileId;
        return rootDirectory.projectVersion.project.creator.removeProject(newProjectId);
      })
      .then(() => rootDirectory.projectVersion.project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ content: '' })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑不存在的文件
  it('it should fail to put a file when the file is not exist', function (done) {
    let newFileId;
    rootDirectory.createEmptyFile()
      .then((file) => {
        newFileId = file.fileId;
        return rootDirectory.removeFile(newFileId);
      })
      .then(() => rootDirectory.projectVersion.project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ content: '' })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可重命名为已存在的路径
  it('it should fail to rename to a exist file', function (done) {
    let existFileName;
    let newFileId;
    rootDirectory.createEmptyFile()
      .then((res) => {
        existFileName = path.basename(res.path);
        return rootDirectory.createEmptyFile();
      })
      .then(({ fileId }) => {
        newFileId = fileId;
        return rootDirectory.projectVersion.project.creator.login();
      })
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ fileName: existFileName })
          .end((err, res) => {
            res.should.have.status(409);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可移动至已存在的路径
  it('it should fail to move to a exist file', function (done) {
    let existFilePath;
    let newFileId;
    rootDirectory.createEmptyFile(files.kind.directory)
      .then((res) => res.createEmptyFile(files.kind.directory))
      .then((res) => res.createEmptyFile())
      .then((res) => {
        existFilePath = res.path;
        return rootDirectory.createEmptyFile();
      })
      .then(({ fileId }) => {
        newFileId = fileId;
        return rootDirectory.projectVersion.project.creator.login();
      })
      .then(() => {
        chai.request(uri)
          .put(url(newFileId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .query({ path: existFilePath })
          .end((err, res) => {
            res.should.have.status(409);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可向文件夹更新内容
  it('it should fail to put a file to the file is directory', function (done) {
    let newDirectoryId;
    rootDirectory.createEmptyFile(files.kind.directory)
      .then(({ fileId }) => {
        newDirectoryId = fileId;
        return rootDirectory.projectVersion.project.creator.login();
      })
      .then(() => {
        chai.request(uri)
          .put(url(newDirectoryId))
          .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
          .send({ content: '' })
          .end((err, res) => {
            res.should.have.status(416);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可重命名或移动根目录
  [
    { fileName: randomstring.generate(8) },
    { path: path.join(randomstring.generate(8), randomstring.generate(8)) },
  ].forEach((edit) => {
    it(`it should fail to put root directory with ${JSON.stringify(edit)}`, function (done) {
      rootDirectory.projectVersion.project.creator.login()
        .then(() => {
          chai.request(uri)
            .put(url())
            .set('Authorization', `Bearer ${rootDirectory.projectVersion.project.creator.token.accessToken}`)
            .query(edit)
            .end((err, res) => {
              res.should.have.status(403);
              common.should.be.errorMessage(res.body);
              done();
            });
        })
        .catch(done);
    });
  });
});
